package com.farm.wcp.controller;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.farm.authority.domain.User;
import com.farm.authority.service.OrganizationServiceInter;
import com.farm.authority.service.UserServiceInter;
import com.farm.category.domain.ClassType;
import com.farm.category.domain.Tag;
import com.farm.category.enums.FuncPOP;
import com.farm.category.service.ClasstypeServiceInter;
import com.farm.category.service.TagServiceInter;
import com.farm.core.page.ViewMode;
import com.farm.core.sql.query.DBRule;
import com.farm.core.sql.query.DataQuery;
import com.farm.core.sql.result.DataResult;
import com.farm.core.time.TimeTool;
import com.farm.learn.domain.ClassHour;
import com.farm.learn.domain.Classt;
import com.farm.learn.service.ClasshourServiceInter;
import com.farm.learn.service.ClasstServiceInter;
import com.farm.learn.service.MajorServiceInter;
import com.farm.parameter.FarmParameterService;
import com.farm.sfile.WdapFileServiceInter;
import com.farm.sfile.domain.FileBase;
import com.farm.sfile.enums.FileModel;
import com.farm.sfile.service.FileBaseServiceInter;
import com.farm.util.web.FarmFormatUnits;
import com.farm.wcp.wsch.WschConfigs;
import com.farm.wcp.wsch.WschIndex;
import com.farm.web.WebUtils;
import com.wcp.question.service.QuestionServiceInter;
import com.wsch.client.WschClient;
import com.wsch.client.domain.WDocVirtualField;
import com.wsch.client.domain.WDocAppDicUnit;
import com.wsch.client.domain.WDocAppModel;
import com.wsch.client.domain.WDocField;
import com.wsch.client.domain.WProjectInfo;
import com.wsch.client.domain.WschUser;
import com.wsch.client.process.PRunner;
import com.wsch.client.process.PState;
import com.wsch.client.process.ProcessRunner;

/**
 * 全文检索相关（使用wsch接口）
 * 
 * @author wangdogn
 *
 */
@RequestMapping("/scindex")
@Controller
public class WschController extends WebUtils {

	@Resource
	private UserServiceInter userServiceImpl;
	@Resource
	private QuestionServiceInter questionServiceImpl;
	@Resource
	private OrganizationServiceInter organizationServiceImpl;
	@Resource
	private MajorServiceInter majorServiceImpl;
	@Resource
	private ClasstServiceInter classTServiceImpl;
	@Resource
	private ClasshourServiceInter classHourServiceImpl;
	@Resource
	private ClasstypeServiceInter classTypeServiceImpl;
	@Resource
	private WdapFileServiceInter wdapFileServiceImpl;
	@Resource
	private TagServiceInter tagServiceImpl;
	@Resource
	private FileBaseServiceInter fileBaseServiceImpl;

	private static final Logger log = Logger.getLogger(WschController.class);

	public static String getThemePath() {
		return FarmParameterService.getInstance().getParameter("config.sys.web.themes.path");
	}

	/**
	 * 首页操作界面
	 */
	@RequestMapping("/list")
	public ModelAndView home(HttpSession session, HttpServletRequest request) {
		ViewMode view = ViewMode.getInstance();
		if (FarmParameterService.getInstance().getParameterBoolean("config.wsch.able")) {
			WschClient client = getWschClient();
			try {
				client.isLive(true);
				String key = FarmParameterService.getInstance().getParameter("config.wsch.project.key");
				WProjectInfo project = client.getProject(key);
				if (project == null) {
					throw new RuntimeException("检索项目不存在:" + key);
				}
				view.putAttr("able", "可用");
				view.putAttr("project", project);
			} catch (Exception e) {
				view.putAttr("error", e.getMessage());
			}
		}
		return view.returnModelAndView("scindex/indexResult");
	}

	private WschClient getWschClient() {
		WschClient client = new WschClient(FarmParameterService.getInstance().getParameter("config.wsch.api.base.url"),
				FarmParameterService.getInstance().getParameter("config.wsch.api.secret"),
				FarmParameterService.getInstance().getParameter("config.wsch.api.loginname"),
				FarmParameterService.getInstance().getParameter("config.wsch.api.password"));
		return client;
	}

	/**
	 * 项目注册操作界面
	 */
	@RequestMapping("/initproject")
	public ModelAndView initproject(HttpSession session, HttpServletRequest request) {
		return ViewMode.getInstance().returnModelAndView("scindex/index-ProjectInit");
	}

	/**
	 * 初始化-索引域
	 * 
	 * @param session
	 * @param request
	 * @return
	 */
	@RequestMapping("/runPDomain")
	@ResponseBody
	public Map<String, Object> registWucEvents(HttpSession session, HttpServletRequest request) {
		try {
			final WschClient client = getWschClient();
			String skey = ProcessRunner.creatInstance(new PRunner() {
				@Override
				public void run(PState state) {
					for (WDocField field : WschConfigs.getFields()) {
						state.setCnum(state.getCnum() + 1);
						client.registField(FarmParameterService.getInstance().getParameter("config.wsch.project.key"),
								field);
					}
				}
			}, WschConfigs.getFields().size(), "runPDomain", true);
			return ViewMode.getInstance().putAttr("skey", skey).returnObjMode();
		} catch (Exception e) {
			return ViewMode.getInstance().setError(e.getMessage(), e).returnObjMode();
		}
	}

	/**
	 * 初始化-索引检索业务
	 * 
	 * @param session
	 * @param request
	 * @return
	 */
	@RequestMapping("/runSCapp")
	@ResponseBody
	public Map<String, Object> runSCapp(HttpSession session, HttpServletRequest request) {
		try {
			final WschClient client = getWschClient();
			String skey = ProcessRunner.creatInstance(new PRunner() {
				@Override
				public void run(PState state) {
					for (WDocAppModel model : WschConfigs.getAppModels()) {
						state.setCnum(state.getCnum() + 1);
						client.registAppModel(
								FarmParameterService.getInstance().getParameter("config.wsch.project.key"), model);
						for (WDocVirtualField field : model.getAppfields()) {
							client.registVirtualField(
									FarmParameterService.getInstance().getParameter("config.wsch.project.key"),
									model.getKey(), field);
						}
					}
				}
			}, WschConfigs.getAppModels().size(), "runSCapp", true);
			return ViewMode.getInstance().putAttr("skey", skey).returnObjMode();
		} catch (Exception e) {
			return ViewMode.getInstance().setError(e.getMessage(), e).returnObjMode();
		}
	}

	/**
	 * 异步服务-进度状态
	 * 
	 * @param session
	 * @param request
	 * @return
	 */
	@RequestMapping("/process")
	@ResponseBody
	public Map<String, Object> processSearchDomain(String skey, HttpSession session, HttpServletRequest request) {
		try {
			ProcessRunner obj = ProcessRunner.findInstance(skey);
			ViewMode view = ViewMode.getInstance();
			if (obj != null) {
				view.putAttr("state", obj.getState());
			} else {
				view.putAttr("state", new PState());
			}
			return view.returnObjMode();
		} catch (Exception e) {
			return ViewMode.getInstance().setError(e.getMessage(), e).returnObjMode();
		}
	}

	/**
	 * 项目注册检索字典界面
	 */
	@RequestMapping("/initSearchDics")
	public ModelAndView initSearchDics(HttpSession session, HttpServletRequest request) {
		List<ClassType> types = classTypeServiceImpl.getAllTypes();
		return ViewMode.getInstance().putAttr("num", types.size()).returnModelAndView("scindex/index-searchDicsInit");
	}

	/**
	 * 更新-检索分类
	 * 
	 * @param session
	 * @param request
	 * @return
	 */
	@RequestMapping("/updateCatalogDic")
	@ResponseBody
	public Map<String, Object> updateCatalogDic(HttpSession session, HttpServletRequest request) {
		try {
			final WschClient client = getWschClient();
			List<ClassType> types = classTypeServiceImpl.getAllTypes();
			// 添加字典子类型
			Collections.sort(types, new Comparator<ClassType>() {
				@Override
				public int compare(ClassType o1, ClassType o2) {
					return o1.getTreecode().length() - o2.getTreecode().length();
				}
			});
			final List<ClassType> abletypes = new ArrayList<ClassType>();

			for (ClassType node : types) {
				// 只同步前三级
				if (node.getTreecode().length() <= 32 * 3) {
					abletypes.add(node);
				}
			}

			String skey = ProcessRunner.creatInstance(new PRunner() {
				@Override
				public void run(PState state) {
					// 初始化字典类型
					String appdicId = client.registAppDic(
							FarmParameterService.getInstance().getParameter("config.wsch.project.key"),
							WschConfigs.getAppDic_Catalog());
					// 删除字典全部子类型
					client.clearAppDicNodes(FarmParameterService.getInstance().getParameter("config.wsch.project.key"),
							appdicId);
					{

						Map<String, String> remoteTypeDic = new HashMap<>();
						for (ClassType type : abletypes) {
							state.setCnum(state.getCnum() + 1);
							String remotetypeid = client.addAppDicNode(
									FarmParameterService.getInstance().getParameter("config.wsch.project.key"),
									appdicId,
									new WDocAppDicUnit(type.getId(), type.getName(), type.getSort(),
											type.getParentid().toUpperCase().equals("NONE") ? appdicId
													: remoteTypeDic.get(type.getParentid())));
							remoteTypeDic.put(type.getId(), remotetypeid);
						}
					}
				}
			}, abletypes.size(), "updateCatalogDic", true);
			return ViewMode.getInstance().putAttr("skey", skey).returnObjMode();
		} catch (Exception e) {
			return ViewMode.getInstance().setError(e.getMessage(), e).returnObjMode();
		}
	}

	/**
	 * 项目注册检索权限界面
	 */
	@RequestMapping("/initSearchPops")
	public ModelAndView initSearchPops(HttpSession session, HttpServletRequest request) {
		List<String> userids = userServiceImpl.getAllLiveUserIds();
		return ViewMode.getInstance().putAttr("num", userids.size()).returnModelAndView("scindex/index-searchPopInit");
	}

	/**
	 * 更新-检索权限
	 * 
	 * @param session
	 * @param request
	 * @return
	 */
	@RequestMapping("/updateSearchPops")
	@ResponseBody
	public Map<String, Object> updateSearchPops(HttpSession session, HttpServletRequest request) {
		try {
			final WschClient client = getWschClient();
			final List<String> userids = userServiceImpl.getAllLiveUserIds();
			String skey = ProcessRunner.creatInstance(new PRunner() {
				@Override
				public void run(PState state) {
					{
						// 清理所有权限组
						client.delPopGroups(FarmParameterService.getInstance().getParameter("config.wsch.project.key"),
								"WLP");
						for (String userid : userids) {
							state.setCnum(state.getCnum() + 1);
							// 清理用户权限组
							// client.delPopGroups(
							// FarmParameterService.getInstance().getParameter("config.wsch.project.key"),
							// userid);
							User user = userServiceImpl.getUserEntity(userid);
							// 同步用户
							WschUser wschuser = client.getUser(user.getLoginname());
							if (wschuser == null) {
								wschuser = new WschUser();
								wschuser.setLoginname(user.getLoginname());
								wschuser.setName(user.getName());
								client.addUser(wschuser);
							} else {
								wschuser.setName(user.getName());
								client.editUser(wschuser);
							}
							// 初始化权限组
							String gourpid = client.initPopGroup(
									FarmParameterService.getInstance().getParameter("config.wsch.project.key"),
									"WLP-" + user.getName(), user.getName());
							// 添加组用户
							client.addUser(gourpid, user.getLoginname());
							List<String> popids = classTypeServiceImpl.getUserAllTypeIds(user, FuncPOP.read);
							// 添加组权限
							client.addPopKey(gourpid, popids);
						}
						{
							// 添加匿名权限组
							state.setCnum(state.getCnum() + 1);
							String gourpid = client.initPopGroup(
									FarmParameterService.getInstance().getParameter("config.wsch.project.key"),
									"ANONYMOUS", "匿名");
							client.addUser(gourpid, "ANONYMOUS");
							// 添加组权限
							List<String> popids = classTypeServiceImpl.getUserAllTypeIds(null, FuncPOP.read);
							client.addPopKey(gourpid, popids);
						}
					}
				}
			}, userids.size() + 1, "updatePopGroup", true);
			return ViewMode.getInstance().putAttr("skey", skey).returnObjMode();
		} catch (Exception e) {
			return ViewMode.getInstance().setError(e.getMessage(), e).returnObjMode();
		}
	}

	/**
	 * 项目注册检索权限界面
	 */
	@RequestMapping("/reIndex")
	public ModelAndView reIndex(HttpSession session, HttpServletRequest request) {
		DataQuery query = DataQuery.getInstance();
		query = classTServiceImpl.createClasstSimpleQuery(query);
		try {
			return ViewMode.getInstance().putAttr("num", query.search().getTotalSize())
					.returnModelAndView("scindex/index-reIndex");
		} catch (SQLException e) {
			return ViewMode.getInstance().putAttr("num", e.getMessage()).returnModelAndView("scindex/index-reIndex");
		}
	}

	/**
	 * 执行索引重建
	 * 
	 * @param session
	 * @param request
	 * @return
	 */
	@RequestMapping("/doReindex")
	@ResponseBody
	public Map<String, Object> doReindex(HttpSession session, HttpServletRequest request) {
		try {
			final WschClient client = getWschClient();
			DataQuery basequery = DataQuery.getInstance();
			basequery.addRule(new DBRule("a.PSTATE", "1", "="));
			basequery = classTServiceImpl.createClasstSimpleQuery(basequery);
			DataResult baseresult = basequery.search();
			final int allPage = baseresult.getTotalPage();
			int allsize = baseresult.getTotalSize();
			String skey = ProcessRunner.creatInstance(new PRunner() {
				@Override
				public void run(PState state) {
					{
						WProjectInfo project = client
								.getProject(FarmParameterService.getInstance().getParameter("config.wsch.project.key"));
						client.removeAllIndex(
								FarmParameterService.getInstance().getParameter("config.wsch.project.key"), "HOUR");
						client.removeAllIndex(
								FarmParameterService.getInstance().getParameter("config.wsch.project.key"), "CLASST");
						String uuid = TimeTool.getTimeDate14();
						for (int page = 1; page <= allPage; page++) {
							DataQuery query = DataQuery.getInstance();
							query.setPagesize(100);
							query.setCurrentPage(page);
							query.addRule(new DBRule("a.PSTATE", "1", "="));
							query = classTServiceImpl.createClasstSimpleQuery(query);
							try {
								DataResult result = query.search();
								for (Map<String, Object> node : result.getResultList()) {
									String classid = (String) node.get("ID");
									Classt classt = classTServiceImpl.getClasstEntity(classid);
									state.setCnum(state.getCnum() + 1);
									FileBase filebase = null;
									if (classt.getImgid() != null) {
										filebase = fileBaseServiceImpl.getFilebaseEntity(classt.getImgid());
									}
									WschIndex index = new WschIndex();
									index.setAPPID(classt.getId());
									index.setAPPKEYID("CLASST");
									index.setAUTHOR(classt.getOutauthor());
									index.setCONTENTS(classt.getShortintro());
									index.setETIME(classt.getEtime());
									if (filebase != null) {
										index.setIMGID(filebase.getId());
										index.setIMGSECRET(filebase.getSecret());
									}
									index.setTAG(getClassTTags(classt));
									index.setTITLE(classt.getName());
									Map<String, String> typeobjs = getClassTPopkeys(classt);
									if (typeobjs != null) {
										index.setPOPKEYS(typeobjs.get("POPKEYS"));
										index.setTREECODE(typeobjs.get("TREECODE"));
										index.setTYPETITLE(typeobjs.get("TITLES"));
									}
									client.addIndex(project.getId(), uuid, index.getMap());
									List<String> hours = classTServiceImpl.getHourids(classid);
									for (String hourid : hours) {
										ClassHour hour = classHourServiceImpl.getClasshourEntity(hourid);
										WschIndex hourindex = new WschIndex();
										hourindex.setAPPID(hour.getId());
										hourindex.setAPPKEYID("HOUR");
										hourindex.setAUTHOR(classt.getOutauthor());
										hourindex.setCONTENTS(classt.getShortintro());
										hourindex.setCLASSID(classt.getId());
										hourindex.setETIME(hour.getEtime());
										hourindex.setTAG(hour.getAltime() + "分钟"+","+classt.getName());
										hourindex.setTITLE(hour.getTitle());
										if (typeobjs != null) {
											hourindex.setPOPKEYS(typeobjs.get("POPKEYS"));
											hourindex.setTREECODE(typeobjs.get("TREECODE"));
											hourindex.setTYPETITLE(typeobjs.get("TITLES"));
										}
										if (filebase != null) {
											hourindex.setIMGID(filebase.getId());
											hourindex.setIMGSECRET(filebase.getSecret());
										}
										client.addIndex(project.getId(), uuid, hourindex.getMap());
									}
								}
								client.runIndex(project.getId(), uuid);
							} catch (SQLException e) {
								throw new RuntimeException(e);
							}
						}
					}
				}
			}, allsize, "reIndex", true);
			return ViewMode.getInstance().putAttr("skey", skey).returnObjMode();
		} catch (Exception e) {
			return ViewMode.getInstance().setError(e.getMessage(), e).returnObjMode();
		}
	}

	/**
	 * 获取分类相关数据（权限keys、treecode、分类标题s）
	 * 
	 * @param classt
	 * @return
	 */
	private Map<String, String> getClassTPopkeys(Classt classt) {
		String typeid = classTServiceImpl.getTypeId(classt.getId());
		Map<String, String> map = new HashMap<String, String>();
		if (StringUtils.isNotBlank(typeid)) {
			ClassType ctype = classTypeServiceImpl.getClasstypeEntity(typeid);
			List<ClassType> types = classTypeServiceImpl.getAllPathType(ctype);
			String popkeys = null;
			String titles = null;
			for (ClassType node : types) {
				if (popkeys == null) {
					popkeys = node.getId();
					titles = node.getName();
				} else {
					popkeys = popkeys + "," + node.getId();
					titles = titles + "/" + node.getName();
				}
			}
			map.put("POPKEYS", popkeys);
			map.put("TREECODE", splitTreeCode(ctype.getTreecode()));
			map.put("TITLES", titles);
			return map;
		}
		return null;
	}

	/**
	 * 用逗号分隔treeId
	 * 
	 * @param treecode
	 * @return
	 */
	private String splitTreeCode(String treecode) {
		StringBuffer back = new StringBuffer();
		for (String node : FarmFormatUnits.getStrList(treecode, 32)) {
			back.append(node).append(",");
		}
		return back.toString();
	}

	/**
	 * 获得课程标签
	 * 
	 * @param classt
	 * @return
	 */
	private String getClassTTags(Classt classt) {
		List<Tag> tags = classTServiceImpl.getClassTags(classt.getId());
		if (tags.size() > 0) {
			String keys = null;
			for (Tag tag : tags) {
				if (keys == null) {
					keys = tag.getName();
				} else {
					keys = keys + "," + tag.getName();
				}
			}
			return keys;
		} else {
			return null;
		}
	}
}
